/*
 * 
 */
package pacMan;

import java.io.IOException;
import java.net.URL;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

/**
 * 
 * Class: SoundEffect
 * Enumeration that will trigger playing a Clip sound effect
 * when called.
 *
 * @author Tomas Rivera
 * @version $Id$
 */
public enum SoundEffect {
	
	//////////////////////////////////////////////////////////
	// Enumeration definitions
	//////////////////////////////////////////////////////////
	
	GAME_START("pacman_beginning.wav"),
	INTERMISSION("pacman_intermission.wav"),
	
	EVENT_PACMAN_EATBONUS("pacman_eatfruit.wav"),
	EVENT_PACMAN_EATGHOST("pacman_eatghost.wav"),
	EVENT_PACMAN_EXTRALIFE("pacman_extrapac.wav"),
	EVENT_PACMAN_KILLED("pacman_death.wav"),
	EVENT_PACMAN_EATPELLET_ODD("waka_1.wav"),
	EVENT_PACMAN_EATPELLET_EVEN("waka_2.wav"),
	
	BKGROUND_PACMAN_SIREN_SLOW("pacman_siren_1.wav"),
	BKGROUND_PACMAN_SIREN_MEDIUM("pacman_siren_2.wav"),
	BKGROUND_PACMAN_SIREN_FAST("pacman_siren_3.wav"),
	BKGROUND_PACMAN_ENERGIZED("pacman_energized.wav"),
	BKGROUND_PACMAN_ENERGIZED_GHOST_EATEN("pacman_ghost_eaten.wav");

	//////////////////////////////////////////////////////////
	// Constructor methods
	//////////////////////////////////////////////////////////
	
	/**
	 * Instantiates a Clip object for the enum definition and loads
	 * the sound file into memory.
	 */
	SoundEffect(String soundFileName) {
		try {
	         URL url = this.getClass().getClassLoader().getResource(soundFileName);
	         AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
	         clip = AudioSystem.getClip();
	         clip.open(audioInputStream);
	         System.out.printf("Opened sound file %s, length %02f sec%n", soundFileName, ((double)clip.getMicrosecondLength()) / 1000);
	      } catch (UnsupportedAudioFileException e) {
	         e.printStackTrace();
	      } catch (IOException e) {
	         e.printStackTrace();
	      } catch (LineUnavailableException e) {
	         e.printStackTrace();
	      }
	}

	//////////////////////////////////////////////////////////
	// Public / Protected methods
	//////////////////////////////////////////////////////////
	
	/**
	 * Starts playing the specified Clip. Returns a reference to that Clip.
	 * 
	 * @return
	 */
	public Clip play() {
		if (clip.isRunning()) {
			clip.stop();
		}
		
		// TODO: Fix mute sound functionality
		//FloatControl gainControl = (FloatControl)clip.getControl(FloatControl.Type.VOLUME);
		//gainControl.setValue(0.0); // Mutes sound
		
		clip.setFramePosition(0);
		
		if (!muteSound) {
			clip.start();
		}
		
		return clip;
	}
	
	/**
	 * Continues a Clip from where it previously left off.
	 * 
	 * @param clip
	 */
	public static void continueClip(Clip clip) {
		if (!clip.isRunning()) {
			clip.start();
		}
	}
	
	/**
	 * Starts playing the specified Clip in an endless loop. 
	 * Returns a reference to that Clip.
	 * 
	 * @return
	 */
	public Clip startLoop() {
		if (clip.isRunning()) {
			clip.stop();
		}
		
		clip.setFramePosition(0);
		
		if (!muteSound) {
			clip.loop(Clip.LOOP_CONTINUOUSLY);
		}
		
		activeLoopingBackgroundClip = clip;
		return clip;
	}
	
	/**
	 * Stops the Clip defined by this enum from playing.
	 */
	public void stop() {
		if (clip.isRunning()) {
			clip.stop();
		}
	}
	
	/**
	 * Starts initialization of all enumeration definitions.
	 */
	static void init() {
		values();
	}
	
	/**
	 * Adds a listener to the Clip for this enum.
	 * @param listener
	 */
	public void addLineListener(LineListener listener) {
		clip.addLineListener(listener);
	}
	
	
	/**
	 * Stop all active sound effects.
	 */
	public static void killAllSoundEffects() {
		SoundEffect.GAME_START.stop();
		SoundEffect.INTERMISSION.stop();
		SoundEffect.EVENT_PACMAN_EATBONUS.stop();
		SoundEffect.EVENT_PACMAN_EATGHOST.stop();
		SoundEffect.EVENT_PACMAN_EXTRALIFE.stop();
		SoundEffect.EVENT_PACMAN_KILLED.stop();
		SoundEffect.EVENT_PACMAN_EATPELLET_ODD.stop();
		SoundEffect.EVENT_PACMAN_EATPELLET_EVEN.stop();
	}
	
	/**
	 * Stop all sound effects that are configured to
	 * play in an endless loop.
	 */
	public static void killAllBackgroundSoundEffects() {
		SoundEffect.BKGROUND_PACMAN_SIREN_SLOW.stop();
		SoundEffect.BKGROUND_PACMAN_SIREN_MEDIUM.stop();
		SoundEffect.BKGROUND_PACMAN_SIREN_FAST.stop();
		SoundEffect.BKGROUND_PACMAN_ENERGIZED.stop();
		SoundEffect.BKGROUND_PACMAN_ENERGIZED_GHOST_EATEN.stop();
	}
	
	/**
	 * Flag sound as muted, and kill all active sound effects.
	 */
	public static void muteSound() {
		muteSound = true;
		killAllSoundEffects();
		killAllBackgroundSoundEffects();
	}
	
	
	public static void unmuteSound() {
		muteSound = false;
		if(activeLoopingBackgroundClip != null) {
			activeLoopingBackgroundClip.loop(Clip.LOOP_CONTINUOUSLY);
		}
	}
	
	//////////////////////////////////////////////////////////
	// Private member variables
	//////////////////////////////////////////////////////////
	
	private Clip clip;
	private static boolean muteSound = false;
	private static Clip activeLoopingBackgroundClip = null;
}
